<template>
  <div class="flow-canvas-container">
    <!-- 工具栏 -->
    <div class="canvas-toolbar">
      <button @click="zoomIn" title="放大">
        <i class="fas fa-search-plus"></i>
      </button>
      <button @click="zoomOut" title="缩小">
        <i class="fas fa-search-minus"></i>
      </button>
      <button @click="zoomToFit" title="适应画布">
        <i class="fas fa-expand"></i>
      </button>
      <button @click="centerNodes" title="居中节点">
        <i class="fas fa-compress"></i>
      </button>
      <button @click="toggleMode" :class="{ active: interactionMode === 'hand' }" title="切换模式">
        <i :class="interactionMode === 'hand' ? 'fas fa-hand-paper' : 'fas fa-mouse-pointer'"></i>
      </button>
    </div>

    <!-- 画布 -->
    <div ref="canvasRef" class="flow-canvas" :class="[interactionMode, { connecting: isConnecting }]" @dragover.prevent
      @drop.prevent="handleDrop" @click="handleCanvasClick" @mousedown="handleCanvasMouseDown" @wheel="handleWheel">
      <!-- 工具按钮 -->
      <div class="json-tool-buttons">
        <button @click="exportJson" title="导出JSON">
          <i class="fas fa-download"></i> 导出
        </button>
        <button @click="triggerImport" title="导入JSON">
          <i class="fas fa-upload"></i> 导入
        </button>
        <input type="file" id="importFileInput" accept=".json" @change="importJson" style="display: none;" />
      </div>

      <!-- 背景网格 -->
      <div class="grid-container"></div>

      <!-- 节点 -->
      <FlowNode v-for="node in nodes" :key="node.id" :node="node" :is-selected="selectedNodes.has(node.id)"
        @select="handleNodeSelect" @update:position="handleNodePositionUpdate" />

      <!-- 选择框 -->
      <div v-if="isSelecting" class="selection-box" :style="{
        left: `${selectionBox.left}px`,
        top: `${selectionBox.top}px`,
        width: `${selectionBox.width}px`,
        height: `${selectionBox.height}px`,
      }"></div>
    </div>

    <!-- 小地图 -->
    <div class="minimap" ref="minimapRef">
      <div class="minimap-content">
        <div v-for="node in nodes" :key="node.id" class="minimap-node"
          :class="[`${node.type}-node`, { selected: selectedNodes.has(node.id) }]" :style="{
            left: `${node.position.x * minimapScale}px`,
            top: `${node.position.y * minimapScale}px`,
          }"></div>
      </div>
      <div class="minimap-viewport" :style="{
        left: `${viewportPosition.x * minimapScale}px`,
        top: `${viewportPosition.y * minimapScale}px`,
        width: `${viewportSize.width * minimapScale}px`,
        height: `${viewportSize.height * minimapScale}px`,
      }"></div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { BrowserJsPlumbInstance, newInstance } from '@jsplumb/browser-ui';
// import { AnchorId } from '@jsplumb/core';
import { BezierConnector } from '@jsplumb/connector-bezier';
import { nextTick, onMounted, ref, watch } from 'vue';
import type { Connection, Node } from '../types';
import FlowNode from './FlowNode.vue';

// Props & Emits
const props = defineProps<{
  nodes: Node[];
  connections: Connection[];
}>();

const emit = defineEmits<{
  (e: 'update:nodes', nodes: Node[]): void;
  (e: 'update:connections', connections: Connection[]): void;
  (e: 'node-select', nodeId: string | null): void;
}>();

// Refs
const canvasRef = ref<HTMLElement | null>(null);
const minimapRef = ref<HTMLElement | null>(null);
const jsPlumb = ref<BrowserJsPlumbInstance | null>(null);

// State
const interactionMode = ref<'pointer' | 'hand'>('pointer');
const isConnecting = ref(false);
const selectedNodes = ref<Set<string>>(new Set());
const zoomLevel = ref(1);
const isSelecting = ref(false);
const selectionBox = ref({ left: 0, top: 0, width: 0, height: 0 });
const minimapScale = ref(0.1);
const viewportPosition = ref({ x: 0, y: 0 });
const viewportSize = ref({ width: 0, height: 0 });
const previousNodes = ref<Node[]>([]);
const currentSourceNodeId = ref<string | null>(null);

// Methods
const setupEndpoints = (el: Element) => {
  if (!jsPlumb.value) return;

  // 清除现有端点
  jsPlumb.value.removeAllEndpoints(el);

  // 获取节点类型
  const nodeType = el.classList.contains('ifelse-node') ? 'ifelse' :
    el.classList.contains('iterator-node') ? 'iterator' :
      el.classList.contains('start-node') ? 'start' :
        el.classList.contains('end-node') ? 'end' : 'default';

  const endpoints = [];

  // 添加左侧输入端点 (除了开始节点)
  if (nodeType !== 'start') {
    const leftEndpoint = jsPlumb.value.addEndpoint(el, {
      anchor: "Left",  // 改为固定的左侧位置
      source: false,
      target: true,
      maxConnections: -1,
      endpoint: {
        type: 'Dot',
        options: {
          radius: 6,
          cssClass: 'input-endpoint',
        }
      },
      paintStyle: {
        fill: '#6c757d',
        stroke: '#6c757d'
      },
      hoverPaintStyle: {
        fill: '#007bff',
        stroke: '#007bff'
      },
      connectorStyle: {
        strokeWidth: 2,
        stroke: '#6c757d',
        outlineWidth: 2,
        outlineStroke: 'transparent'
      },
      connectorHoverStyle: {
        stroke: '#007bff'
      },
      connector: {
        type: BezierConnector.type,
        options: {
          curviness: 50,
          gap: 8,
          cornerRadius: 10,
          stub: [30, 30],
          alwaysRespectStubs: true,
        }
      }
    });

    endpoints.push(leftEndpoint);
  }

  // 添加右侧输出端点 (根据节点类型)
  if (nodeType === 'ifelse') {
    // 为条件节点添加两个右侧端点 - 一个表示真(上)，一个表示假(下)
    const trueEndpoint = jsPlumb.value.addEndpoint(el, {
      anchor: [1, 0.3, 1, 0],  // 右侧靠上位置
      source: true,
      target: false,
      maxConnections: -1,
      endpoint: {
        type: 'Dot',
        options: {
          radius: 6,
        }
      },
      paintStyle: {
        fill: '#28a745', // 绿色表示真
        stroke: '#28a745'
      },
      hoverPaintStyle: {
        fill: '#34ce57',
        stroke: '#34ce57'
      },
      connectorStyle: {
        strokeWidth: 2,
        stroke: '#6c757d',
        outlineWidth: 2,
        outlineStroke: 'transparent'
      },
      connectorHoverStyle: {
        stroke: '#007bff'
      },
      connector: {
        type: BezierConnector.type,
        options: {
          curviness: 50,
          gap: 8,
          cornerRadius: 10,
          stub: [30, 30],
          alwaysRespectStubs: true,
        }
      }
    });

    const falseEndpoint = jsPlumb.value.addEndpoint(el, {
      anchor: [1, 0.7, 1, 0],  // 右侧靠下位置
      source: true,
      target: false,
      maxConnections: -1,
      endpoint: {
        type: 'Dot',
        options: {
          radius: 6,
        }
      },
      paintStyle: {
        fill: '#dc3545', // 红色表示假
        stroke: '#dc3545'
      },
      hoverPaintStyle: {
        fill: '#e4606d',
        stroke: '#e4606d'
      },
      connectorStyle: {
        strokeWidth: 2,
        stroke: '#6c757d',
        outlineWidth: 2,
        outlineStroke: 'transparent'
      },
      connectorHoverStyle: {
        stroke: '#007bff'
      },
      connector: {
        type: BezierConnector.type,
        options: {
          curviness: 50,
          gap: 8,
          cornerRadius: 10,
          stub: [30, 30],
          alwaysRespectStubs: true,
        }
      }
    });

    endpoints.push(trueEndpoint, falseEndpoint);
  }
  else if (nodeType === 'iterator') {
    // 为迭代器节点添加两个右侧端点 - 一个表示循环体(上)，一个表示完成(下)
    const loopEndpoint = jsPlumb.value.addEndpoint(el, {
      anchor: [1, 0.3, 1, 0],  // 右侧靠上位置
      source: true,
      target: false,
      maxConnections: -1,
      endpoint: {
        type: 'Dot',
        options: {
          radius: 6,
        }
      },
      paintStyle: {
        fill: '#20c997', // 青色表示循环
        stroke: '#20c997'
      },
      hoverPaintStyle: {
        fill: '#3dd5ac',
        stroke: '#3dd5ac'
      },
      connectorStyle: {
        strokeWidth: 2,
        stroke: '#6c757d',
        outlineWidth: 2,
        outlineStroke: 'transparent'
      },
      connectorHoverStyle: {
        stroke: '#007bff'
      },
      connector: {
        type: BezierConnector.type,
        options: {
          curviness: 50,
          gap: 8,
          cornerRadius: 10,
          stub: [30, 30],
          alwaysRespectStubs: true,
        }
      }
    });

    const doneEndpoint = jsPlumb.value.addEndpoint(el, {
      anchor: [1, 0.7, 1, 0],  // 右侧靠下位置
      source: true,
      target: false,
      maxConnections: -1,
      endpoint: {
        type: 'Dot',
        options: {
          radius: 6,
        }
      },
      paintStyle: {
        fill: '#fd7e14', // 橙色表示完成
        stroke: '#fd7e14'
      },
      hoverPaintStyle: {
        fill: '#fd9843',
        stroke: '#fd9843'
      },
      connectorStyle: {
        strokeWidth: 2,
        stroke: '#6c757d',
        outlineWidth: 2,
        outlineStroke: 'transparent'
      },
      connectorHoverStyle: {
        stroke: '#007bff'
      },
      connector: {
        type: BezierConnector.type,
        options: {
          curviness: 50,
          gap: 8,
          cornerRadius: 10,
          stub: [30, 30],
          alwaysRespectStubs: true,
        }
      }
    });

    endpoints.push(loopEndpoint, doneEndpoint);
  }
  else if (nodeType !== 'end') {  // 对结束节点不添加右侧连接点
    // 默认节点只有一个右侧端点
    const rightEndpoint = jsPlumb.value.addEndpoint(el, {
      anchor: "Right",  // 改为固定的右侧位置
      source: true,
      target: false,
      maxConnections: -1,
      endpoint: {
        type: 'Dot',
        options: {
          radius: 6,
        }
      },
      paintStyle: {
        fill: '#6c757d',
        stroke: '#6c757d'
      },
      hoverPaintStyle: {
        fill: '#007bff',
        stroke: '#007bff'
      },
      connectorStyle: {
        strokeWidth: 2,
        stroke: '#6c757d',
        outlineWidth: 2,
        outlineStroke: 'transparent'
      },
      connectorHoverStyle: {
        stroke: '#007bff'
      },
      connector: {
        type: BezierConnector.type,
        options: {
          curviness: 50,
          gap: 8,
          cornerRadius: 10,
          stub: [30, 30],
          alwaysRespectStubs: true,
        }
      }
    });

    endpoints.push(rightEndpoint);
  }

  // 使用原生拖拽实现
  let isDragging = false;
  let startX = 0;
  let startY = 0;
  let originalX = 0;
  let originalY = 0;

  const handleMouseDown = (event: Event) => {
    const e = event as MouseEvent;
    if ((e.target as Element).closest('.jtk-endpoint')) {
      return;
    }

    isDragging = true;
    startX = e.clientX;
    startY = e.clientY;

    const rect = el.getBoundingClientRect();
    const canvas = canvasRef.value;
    if (canvas) {
      const canvasRect = canvas.getBoundingClientRect();
      originalX = (rect.left - canvasRect.left) / zoomLevel.value + canvas.scrollLeft;
      originalY = (rect.top - canvasRect.top) / zoomLevel.value + canvas.scrollTop;
    }

    const handleMouseMove = (moveEvent: Event) => {
      const e = moveEvent as MouseEvent;
      if (!isDragging || !canvasRef.value) return;

      const dx = (e.clientX - startX) / zoomLevel.value;
      const dy = (e.clientY - startY) / zoomLevel.value;

      const newX = Math.round((originalX + dx) / 5) * 5;
      const newY = Math.round((originalY + dy) / 5) * 5;

      const nodeIndex = props.nodes.findIndex(n => n.id === el.id);
      if (nodeIndex >= 0) {
        const nodes = [...props.nodes];
        nodes[nodeIndex] = {
          ...nodes[nodeIndex],
          position: { x: newX, y: newY }
        };
        emit('update:nodes', nodes);

        // 减少重绘频率
        if (newX % 10 === 0 || newY % 10 === 0) {
          jsPlumb.value?.repaintEverything();
        }
      }
    };

    const handleMouseUp = () => {
      if (!isDragging) return;

      isDragging = false;
      document.removeEventListener('mousemove', handleMouseMove);
      document.removeEventListener('mouseup', handleMouseUp);
      jsPlumb.value?.repaintEverything();
    };

    document.addEventListener('mousemove', handleMouseMove);
    document.addEventListener('mouseup', handleMouseUp);
  };

  el.addEventListener('mousedown', handleMouseDown);

  return { endpoints };
};

const initializeJsPlumb = async () => {
  if (!canvasRef.value) return;

  try {
    if (jsPlumb.value) {
      jsPlumb.value.destroy();
    }

    jsPlumb.value = newInstance({
      container: canvasRef.value,
      // 连接线配置
      connector: {
        type: BezierConnector.type,
        options: {
          curviness: 50,
          gap: 8,
          cornerRadius: 10,
          stub: [30, 30],
          alwaysRespectStubs: true,
        },
      },
      // 连接线样式
      paintStyle: {
        strokeWidth: 2,
        stroke: '#6c757d',
        outlineWidth: 2,
        outlineStroke: 'transparent',
      },
      hoverPaintStyle: {
        stroke: '#007bff',
      },
      // 端点默认配置
      endpoint: {
        type: 'Dot',
        options: {
          radius: 5,
        },
      },
      // 禁用默认样式
      endpointStyle: { fill: 'transparent' },
      // 拖动配置
      dragOptions: {
        cursor: 'move',
        // 确保拖动时连接一直跟随
        start: function () {
          isConnecting.value = false;
        },
        drag: function () {
          jsPlumb.value?.repaintEverything();
        },
        stop: function () {
          jsPlumb.value?.repaintEverything();
        }
      },
      // 连接配置
      connectionOverlays: [
        {
          type: 'Arrow',
          options: {
            location: 1,
            width: 10,
            length: 10,
          },
        },
      ],
      // 添加默认锚点配置
      anchors: [
        "Right",  // source
        "Left"    // target
      ],
      // 添加连接验证
      beforeDrop: (params: any) => {
        // 确保只能从source连接到target
        const sourceEndpoint = params.connection.endpoints[0];
        const targetEndpoint = params.connection.endpoints[1];

        // 检查是否是同一个节点
        if (sourceEndpoint.node.id === targetEndpoint.node.id) {
          console.log("不能连接到自己的节点");
          return false;
        }

        return sourceEndpoint.isSource && targetEndpoint.isTarget;
      }
    });

    // 初始化所有节点的端点
    const initializeNodeEndpoints = async () => {
      await nextTick();
      props.nodes.forEach(node => {
        const element = document.getElementById(node.id);
        if (element) {
          setupEndpoints(element);
        }
      });
      jsPlumb.value?.repaintEverything();
    };

    // 初始化端点
    await initializeNodeEndpoints();

    // 修改 watch 函数
    watch(() => props.nodes, async (newNodes, oldNodes) => {
      // 找出新增的节点
      const addedNodes = newNodes.filter(node =>
        !oldNodes.some(oldNode => oldNode.id === node.id)
      );

      // 找出被移动的节点
      const movedNodes = newNodes.filter(node => {
        const oldNode = oldNodes.find(old => old.id === node.id);
        return oldNode && (
          oldNode.position.x !== node.position.x ||
          oldNode.position.y !== node.position.y
        );
      });

      // 找出被删除的节点
      const deletedNodes = oldNodes.filter(oldNode =>
        !newNodes.some(node => node.id === oldNode.id)
      );

      await nextTick();

      if (!jsPlumb.value) return;

      // 处理新增节点
      addedNodes.forEach(node => {
        const element = document.getElementById(node.id);
        if (element) {
          setupEndpoints(element);
        }
      });

      // 处理移动的节点
      movedNodes.forEach(node => {
        const element = document.getElementById(node.id);
        if (element) {
          jsPlumb.value?.revalidate(element);
        }
      });

      // 处理删除的节点
      deletedNodes.forEach(node => {
        const element = document.getElementById(node.id);
        if (element) {
          jsPlumb.value?.removeAllEndpoints(element);
        }
      });

      // 只在必要时重绘
      if (addedNodes.length > 0 || deletedNodes.length > 0) {
        jsPlumb.value.repaintEverything();
      }

      previousNodes.value = [...newNodes];
    }, { deep: true });

    // 监听节点添加事件
    const observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        mutation.addedNodes.forEach((node) => {
          if (node instanceof Element && node.classList.contains('flow-node')) {
            nextTick(() => {
              setupEndpoints(node);
              jsPlumb.value?.repaintEverything();
            });
          }
        });
      });
    });

    observer.observe(canvasRef.value, { childList: true, subtree: true });

    // 监听jsPlumb相关事件
    jsPlumb.value.bind('beforeDrag', (params) => {
      // 表示正在创建连接
      isConnecting.value = true;
      currentSourceNodeId.value = params.sourceId;
      console.log("开始拖动连接线，源节点:", params.sourceId);

      // 标记源节点
      const sourceElement = document.getElementById(params.sourceId);
      if (sourceElement) {
        sourceElement.classList.add('source-node');
      }

      // 通过CSS类控制端点显示
      document.body.classList.add('connecting');

      // 添加全局鼠标事件以检测连接取消
      document.addEventListener('mouseup', handleGlobalMouseUp);
    });

    // 全局鼠标事件处理 - 用于检测连接取消
    const handleGlobalMouseUp = () => {
      setTimeout(() => {
        // 如果isConnecting还是true，说明没有触发connection事件，认为是取消了连接
        if (isConnecting.value) {
          console.log("检测到鼠标释放但连接未完成，视为取消连接");
          isConnecting.value = false;

          // 移除连接状态样式
          document.body.classList.remove('connecting');

          // 移除源节点标记
          if (currentSourceNodeId.value) {
            const sourceElement = document.getElementById(currentSourceNodeId.value);
            if (sourceElement) {
              sourceElement.classList.remove('source-node');
            }
          }
          currentSourceNodeId.value = null;

          // 强制隐藏所有未连接的端点
          hideAllLeftEndpoints();
        }

        // 移除事件监听器
        document.removeEventListener('mouseup', handleGlobalMouseUp);
      }, 50); // 短暂延迟确保先处理连接事件
    };

    jsPlumb.value.bind('connectionDrag', () => {
      // 连接线被拖动时保持connecting状态
      isConnecting.value = true;
    });

    jsPlumb.value.bind('connection', (info) => {
      console.log("连接创建成功");

      // 移除连接状态
      isConnecting.value = false;

      // 移除mouseup监听，避免重复处理
      document.removeEventListener('mouseup', handleGlobalMouseUp);

      // 移除连接状态样式
      document.body.classList.remove('connecting');

      // 移除源节点标记
      if (currentSourceNodeId.value) {
        const sourceElement = document.getElementById(currentSourceNodeId.value);
        if (sourceElement) {
          sourceElement.classList.remove('source-node');
        }
      }
      currentSourceNodeId.value = null;

      // 确保这个连接不会因为拖动而断开
      if (info.connection) {
        info.connection.setDetachable(false);
      }

      const connection: Connection = {
        id: info.connection.id,
        source: info.source.id,
        target: info.target.id,
      };
      emit('update:connections', [...props.connections, connection]);

      // 连接创建后立即更新端点显示
      hideAllLeftEndpoints();
    });

    // 连接断开时
    jsPlumb.value.bind('connectionDetached', (info) => {
      console.log("连接断开");

      // 更新连接列表
      const connections = props.connections.filter((conn) => conn.id !== info.connection.id);
      emit('update:connections', connections);

      // 更新状态
      isConnecting.value = false;
      currentSourceNodeId.value = null;

      // 移除连接状态样式
      document.body.classList.remove('connecting');

      // 立即隐藏所有左侧端点
      hideAllLeftEndpoints();
    });

    // 添加一个强制隐藏所有左侧端点的函数
    const hideAllLeftEndpoints = () => {
      console.log("更新所有左侧端点状态");

      // 获取已连接的目标节点
      const connectedTargets = new Set(props.connections.map(conn => conn.target));

      // 遍历所有节点
      props.nodes.forEach(node => {
        if (node.type === 'start') return; // 开始节点没有左侧端点

        const element = document.getElementById(node.id);
        if (!element) return;

        try {
          const allEndpoints = jsPlumb.value?.getEndpoints(element) || [];
          const inputEndpoints = allEndpoints.filter(ep => !ep.isSource && ep.isTarget);

          inputEndpoints.forEach(endpoint => {
            try {
              // 使用as any以绕过TypeScript限制，因jsPlumb类型定义可能不完整
              const canvas = (endpoint as any).canvas || (endpoint.endpoint as any)?.canvas;
              if (!canvas) return;

              const el = canvas as HTMLElement;

              // 移除先前可能添加的CSS类
              el.classList.remove('connected-endpoint');

              // 如果不是连接目标，强制隐藏
              if (!connectedTargets.has(node.id)) {
                el.style.opacity = '0';
                el.style.visibility = 'hidden';
              } else {
                // 已连接的节点保持可见并添加连接类
                el.style.opacity = '1';
                el.style.visibility = 'visible';
                el.classList.add('connected-endpoint');
              }
            } catch (err) {
              console.error("处理端点显示时出错:", err);
            }
          });
        } catch (err) {
          console.error("获取节点端点时出错:", err);
        }
      });
    };

    // 保持已连接端点的状态
    const updateConnectedEndpoints = () => {
      // 获取所有已连接的目标节点
      const connectedTargets = new Set(props.connections.map(conn => conn.target));

      // 遍历所有节点，为已连接的端点添加类
      props.nodes.forEach(node => {
        if (node.type === 'start') return;

        const element = document.getElementById(node.id);
        if (!element) return;

        const allEndpoints = jsPlumb.value?.getEndpoints(element) || [];
        const inputEndpoints = allEndpoints.filter(ep => !ep.isSource && ep.isTarget);

        inputEndpoints.forEach(endpoint => {
          if (!endpoint.canvas) return;

          const el = endpoint.canvas as HTMLElement;

          // 清除所有相关类
          el.classList.remove('connected-endpoint');

          // 为已连接节点添加类
          if (connectedTargets.has(node.id)) {
            el.classList.add('connected-endpoint');
          }
        });
      });
    };

    // 当连接完成后，标记已连接的端点
    props.connections.forEach(conn => {
      try {
        const sourceElement = document.getElementById(conn.source);
        const targetElement = document.getElementById(conn.target);

        if (sourceElement && targetElement) {
          const connection = jsPlumb.value?.connect({
            source: sourceElement,
            target: targetElement,
            id: conn.id,
            detachable: false
          });

          if (connection) {
            console.log(`恢复连接: ${conn.source} -> ${conn.target}`);
          }
        }
      } catch (error) {
        console.error('Failed to restore connection:', error);
      }
    });

    // 初始化完成后，更新连接状态
    updateConnectedEndpoints();

    // 重新绘制所有连接
    await nextTick();
    jsPlumb.value.repaintEverything();
  } catch (error) {
    console.error('Error initializing jsPlumb:', error);
  }
};

const handleDrop = (event: DragEvent) => {
  if (!canvasRef.value) return;

  const nodeType = event.dataTransfer?.getData('node-type');
  if (!nodeType) return;

  const rect = canvasRef.value.getBoundingClientRect();
  const position = {
    x: (event.clientX - rect.left) / zoomLevel.value + canvasRef.value.scrollLeft,
    y: (event.clientY - rect.top) / zoomLevel.value + canvasRef.value.scrollTop,
  };

  // 为不同类型的节点设置中文名称
  const nodeNameMap: Record<string, string> = {
    start: '开始节点',
    model: '大模型节点',
    end: '结果节点',
    agent: '智能体节点',
    ifelse: '条件判断节点',
    iterator: '迭代器节点',
    code: '代码节点',
    template: '模板转换节点',
    http: 'HTTP节点',
    database: '数据库节点',
    email: '邮件节点',
  };

  const nodeName = nodeNameMap[nodeType] || `新${nodeType}节点`;

  const newNode: Node = {
    id: `node-${Date.now()}`,
    type: nodeType,
    position,
    name: nodeName,
    title: nodeName,
    icon: 'fas fa-cog',
    color: '#007bff',
    endpoints: {
      input: [],
      output: []
    },
    params: {
      input: [],
      output: [],
    },
  };

  emit('update:nodes', [...props.nodes, newNode]);
};

const handleCanvasClick = () => {
  selectedNodes.value.clear();
  emit('node-select', null);
};

const handleNodeSelect = (nodeId: string) => {
  if (selectedNodes.value.has(nodeId)) {
    selectedNodes.value.delete(nodeId);
  } else {
    if (event instanceof MouseEvent && event.shiftKey) {
      selectedNodes.value.add(nodeId);
    } else {
      selectedNodes.value.clear();
      selectedNodes.value.add(nodeId);
    }
  }
  emit('node-select', nodeId);
};

const handleNodePositionUpdate = (nodeId: string, position: { x: number; y: number }) => {
  const nodes = [...props.nodes];
  const nodeIndex = nodes.findIndex((n) => n.id === nodeId);
  if (nodeIndex !== -1) {
    nodes[nodeIndex] = { ...nodes[nodeIndex], position };
    emit('update:nodes', nodes);
  }
};

const handleCanvasMouseDown = (event: MouseEvent) => {
  if (event.button !== 0 || !canvasRef.value) return;

  // 如果点击的是节点或其子元素，或者正在进行连线，不启动选择框
  const target = event.target as Element;
  if (target.closest('.flow-node') || target.closest('.jtk-endpoint') ||
    target.closest('.jtk-connector') || isConnecting.value) {
    return;
  }

  const startX = event.clientX;
  const startY = event.clientY;
  const startScrollLeft = canvasRef.value.scrollLeft;
  const startScrollTop = canvasRef.value.scrollTop;

  if (interactionMode.value === 'hand') {
    // 平移模式
    const handleMouseMove = (e: MouseEvent) => {
      if (!canvasRef.value) return;
      const dx = e.clientX - startX;
      const dy = e.clientY - startY;
      canvasRef.value.scrollLeft = startScrollLeft - dx;
      canvasRef.value.scrollTop = startScrollTop - dy;

      // 重新绘制连接
      jsPlumb.value?.repaintEverything();
    };

    const handleMouseUp = () => {
      document.removeEventListener('mousemove', handleMouseMove);
      document.removeEventListener('mouseup', handleMouseUp);
    };

    document.addEventListener('mousemove', handleMouseMove);
    document.addEventListener('mouseup', handleMouseUp);
  } else {
    // 选择模式，但确保不在连线过程中
    if (isConnecting.value) return;

    isSelecting.value = true;
    selectionBox.value = {
      left: event.clientX,
      top: event.clientY,
      width: 0,
      height: 0,
    };

    const handleMouseMove = (e: MouseEvent) => {
      const width = e.clientX - startX;
      const height = e.clientY - startY;

      selectionBox.value = {
        left: width > 0 ? startX : e.clientX,
        top: height > 0 ? startY : e.clientY,
        width: Math.abs(width),
        height: Math.abs(height),
      };

      // 检查节点是否在选择框内
      checkNodesInSelection();
    };

    const handleMouseUp = () => {
      isSelecting.value = false;
      document.removeEventListener('mousemove', handleMouseMove);
      document.removeEventListener('mouseup', handleMouseUp);
    };

    document.addEventListener('mousemove', handleMouseMove);
    document.addEventListener('mouseup', handleMouseUp);
  }
};

const checkNodesInSelection = () => {
  if (!canvasRef.value) return;

  const rect = canvasRef.value.getBoundingClientRect();
  const scale = zoomLevel.value;
  const scrollLeft = canvasRef.value.scrollLeft;
  const scrollTop = canvasRef.value.scrollTop;

  const selectionRect = {
    left: (selectionBox.value.left - rect.left) / scale + scrollLeft,
    top: (selectionBox.value.top - rect.top) / scale + scrollTop,
    right: (selectionBox.value.left + selectionBox.value.width - rect.left) / scale + scrollLeft,
    bottom: (selectionBox.value.top + selectionBox.value.height - rect.top) / scale + scrollTop,
  };

  selectedNodes.value.clear();
  props.nodes.forEach((node) => {
    if (
      node.position.x >= selectionRect.left &&
      node.position.x <= selectionRect.right &&
      node.position.y >= selectionRect.top &&
      node.position.y <= selectionRect.bottom
    ) {
      selectedNodes.value.add(node.id);
    }
  });
};

const handleWheel = (event: WheelEvent) => {
  if (event.ctrlKey || event.metaKey) {
    event.preventDefault();
    const delta = event.deltaY > 0 ? -0.1 : 0.1;
    const newZoom = Math.max(0.5, Math.min(2, zoomLevel.value + delta));
    zoomAtPoint(newZoom, event.clientX, event.clientY);
  }
};

const zoomIn = () => {
  const newZoom = Math.min(2, zoomLevel.value + 0.1);
  zoom(newZoom);
};

const zoomOut = () => {
  const newZoom = Math.max(0.5, zoomLevel.value - 0.1);
  zoom(newZoom);
};

const zoom = (scale: number) => {
  if (!canvasRef.value) return;
  const rect = canvasRef.value.getBoundingClientRect();
  zoomAtPoint(scale, rect.width / 2, rect.height / 2);
  nextTick(() => {
    jsPlumb.value?.repaintEverything();
  });
};

const zoomAtPoint = (scale: number, clientX: number, clientY: number) => {
  if (!canvasRef.value) return;

  const rect = canvasRef.value.getBoundingClientRect();
  const x = (clientX - rect.left) / zoomLevel.value + canvasRef.value.scrollLeft;
  const y = (clientY - rect.top) / zoomLevel.value + canvasRef.value.scrollTop;

  zoomLevel.value = scale;

  nextTick(() => {
    if (!canvasRef.value) return;
    const newX = (clientX - rect.left) / scale + canvasRef.value.scrollLeft;
    const newY = (clientY - rect.top) / scale + canvasRef.value.scrollTop;

    canvasRef.value.scrollLeft += x - newX;
    canvasRef.value.scrollTop += y - newY;
  });
};

const zoomToFit = () => {
  if (!canvasRef.value || props.nodes.length === 0) return;

  const bounds = props.nodes.reduce(
    (acc, node) => {
      acc.left = Math.min(acc.left, node.position.x);
      acc.top = Math.min(acc.top, node.position.y);
      acc.right = Math.max(acc.right, node.position.x + 200);
      acc.bottom = Math.max(acc.bottom, node.position.y + 100);
      return acc;
    },
    { left: Infinity, top: Infinity, right: -Infinity, bottom: -Infinity }
  );

  const padding = 50;
  const width = bounds.right - bounds.left + padding * 2;
  const height = bounds.bottom - bounds.top + padding * 2;
  const rect = canvasRef.value.getBoundingClientRect();

  const scaleX = rect.width / width;
  const scaleY = rect.height / height;
  const scale = Math.min(Math.min(scaleX, scaleY), 1);

  zoom(scale);

  nextTick(() => {
    if (!canvasRef.value) return;
    canvasRef.value.scrollLeft = bounds.left - padding;
    canvasRef.value.scrollTop = bounds.top - padding;
  });
};

const centerNodes = () => {
  if (!canvasRef.value || props.nodes.length === 0) return;

  const bounds = props.nodes.reduce(
    (acc, node) => {
      acc.left = Math.min(acc.left, node.position.x);
      acc.top = Math.min(acc.top, node.position.y);
      acc.right = Math.max(acc.right, node.position.x + 200);
      acc.bottom = Math.max(acc.bottom, node.position.y + 100);
      return acc;
    },
    { left: Infinity, top: Infinity, right: -Infinity, bottom: -Infinity }
  );

  const centerX = (bounds.left + bounds.right) / 2;
  const centerY = (bounds.top + bounds.bottom) / 2;
  const rect = canvasRef.value.getBoundingClientRect();

  canvasRef.value.scrollLeft = centerX - rect.width / 2;
  canvasRef.value.scrollTop = centerY - rect.height / 2;
};

const toggleMode = () => {
  interactionMode.value = interactionMode.value === 'pointer' ? 'hand' : 'pointer';
};

const updateMinimapViewport = () => {
  if (!canvasRef.value || !minimapRef.value) return;

  const rect = canvasRef.value.getBoundingClientRect();
  viewportSize.value = {
    width: rect.width,
    height: rect.height,
  };

  viewportPosition.value = {
    x: canvasRef.value.scrollLeft || 0,
    y: canvasRef.value.scrollTop || 0
  };
};

// 导出JSON功能
const exportJson = () => {
  const data = {
    nodes: props.nodes,
    connections: props.connections,
  };

  // 创建Blob对象
  const jsonString = JSON.stringify(data, null, 2);
  const blob = new Blob([jsonString], { type: 'application/json' });

  // 创建下载链接
  const url = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.download = `flow-${new Date().toISOString().slice(0, 10)}.json`;

  // 触发下载
  document.body.appendChild(link);
  link.click();

  // 清理
  URL.revokeObjectURL(url);
  document.body.removeChild(link);
};

// 导入JSON功能
const importJson = (event: Event) => {
  const fileInput = event.target as HTMLInputElement;
  const file = fileInput.files?.[0];

  if (!file) return;

  const reader = new FileReader();
  reader.onload = (e) => {
    try {
      const data = JSON.parse(e.target?.result as string);

      if (data.nodes && Array.isArray(data.nodes) &&
        data.connections && Array.isArray(data.connections)) {

        console.log('开始导入流程图，节点数:', data.nodes.length, '连线数:', data.connections.length);

        // 清空当前节点和连线
        emit('update:nodes', []);
        emit('update:connections', []);

        // 在重置jsPlumb之前保存实例
        const jsPlumbInstance = jsPlumb.value;

        // 等待节点和连线数组清空
        nextTick(async () => {
          // 等待一小段时间确保DOM已更新
          await new Promise(resolve => setTimeout(resolve, 50));

          // 重置jsPlumb实例而不是重新创建
          if (jsPlumbInstance) {
            console.log('重置jsPlumb实例...');
            jsPlumbInstance.reset(); // 仅清除连线和端点，但保持事件监听器和设置

            // 导入节点数据
            console.log('导入节点数据...');
            emit('update:nodes', data.nodes);

            // 等待节点渲染到DOM
            await nextTick();
            await new Promise(resolve => setTimeout(resolve, 50));

            // 重新初始化所有节点的端点
            console.log('初始化节点端点...');
            data.nodes.forEach(node => {
              const element = document.getElementById(node.id);
              if (element) {
                setupEndpoints(element);
              } else {
                console.warn(`找不到节点元素: ${node.id}`);
              }
            });

            // 再次等待端点初始化完成
            await nextTick();
            await new Promise(resolve => setTimeout(resolve, 50));

            // 导入连线数据
            console.log('导入连线数据...');
            emit('update:connections', data.connections);

            // 等待连线数据更新
            await nextTick();
            await new Promise(resolve => setTimeout(resolve, 50));

            // 创建连线
            console.log('创建连线...');
            data.connections.forEach(conn => {
              try {
                const sourceElement = document.getElementById(conn.source);
                const targetElement = document.getElementById(conn.target);

                if (sourceElement && targetElement) {
                  jsPlumbInstance.connect({
                    source: sourceElement,
                    target: targetElement,
                    id: conn.id,
                    detachable: false
                  });
                } else {
                  console.warn(`无法找到连接节点: source=${conn.source}, target=${conn.target}`);
                }
              } catch (error) {
                console.error('创建连线失败:', conn, error);
              }
            });

            // 重绘所有连线
            jsPlumbInstance.repaintEverything();
            console.log('导入流程图完成');
          }
        });
      } else {
        alert('无效的JSON格式，缺少nodes或connections数组');
      }
    } catch (error) {
      console.error('解析JSON失败:', error);
      alert('JSON解析失败，请检查文件格式');
    }

    // 重置文件输入，以便可以再次选择同一文件
    fileInput.value = '';
  };

  reader.readAsText(file);
};

// 触发文件选择
const triggerImport = () => {
  const fileInput = document.getElementById('importFileInput');
  fileInput?.click();
};

// Lifecycle
onMounted(async () => {
  await initializeJsPlumb();

  // 确保jsPlumb实例可以通过DOM元素访问
  if (canvasRef.value && jsPlumb.value) {
    // 将jsPlumb实例绑定到DOM元素，方便外部访问
    (canvasRef.value as any).__jsPlumb = jsPlumb.value;
  }

  window.addEventListener('resize', updateMinimapViewport);
  if (canvasRef.value) {
    canvasRef.value.addEventListener('scroll', updateMinimapViewport);
  }
  updateMinimapViewport();
});

// 使用defineExpose暴露方法给父组件
defineExpose({
  zoomIn,
  zoomOut,
  zoomToFit,
  centerNodes,
  // 提供jsPlumb实例访问方法
  getJsPlumb: () => {
    return jsPlumb.value;
  },
  // 添加一个完全重新初始化jsPlumb的方法
  reinitializeJsPlumb: async () => {
    console.log('完全重新初始化jsPlumb...');
    try {
      // 销毁现有实例
      if (jsPlumb.value) {
        jsPlumb.value.destroy();
        jsPlumb.value = null;
      }

      // 重新初始化实例
      await initializeJsPlumb();
      console.log('jsPlumb实例重新初始化完成');
      return true;
    } catch (error) {
      console.error('jsPlumb重新初始化失败:', error);
      return false;
    }
  },
  // 修改重绘方法，确保所有连线显示
  repaintEverything: async () => {
    console.log('重绘所有连线，当前连线数:', props.connections.length);
    if (jsPlumb.value) {
      try {
        // 确保DOM已更新
        await nextTick();

        // 检查每个连接是否已存在，不存在则创建
        for (const conn of props.connections) {
          try {
            const sourceElement = document.getElementById(conn.source);
            const targetElement = document.getElementById(conn.target);

            if (!sourceElement || !targetElement) {
              console.warn(`无法找到连接的节点: source=${conn.source}, target=${conn.target}`);
              continue;
            }

            // 检查是否已有此连接ID
            const existingConn = jsPlumb.value.getConnections().find(c => c.id === conn.id);
            if (existingConn) {
              console.log(`连接 ${conn.id} 已存在，重新验证`);
              jsPlumb.value.revalidate(sourceElement);
              jsPlumb.value.revalidate(targetElement);
            } else {
              console.log(`创建新连接: ${conn.id} (${conn.source} -> ${conn.target})`);
              jsPlumb.value.connect({
                source: sourceElement,
                target: targetElement,
                id: conn.id,
                detachable: false
              });
            }
          } catch (error) {
            console.error('处理连接失败:', conn, error);
          }
        }

        // 最后全局重绘
        jsPlumb.value.repaintEverything();
        console.log('连线重绘完成');
      } catch (error) {
        console.error('重绘连线失败:', error);
      }
    } else {
      console.warn('jsPlumb实例不存在，无法重绘连线');
    }
  },
  // 导出JSON相关方法
  exportJson,
  importJson,
  triggerImport
});
</script>

<style scoped>
.flow-canvas-container {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.canvas-toolbar {
  position: absolute;
  top: 16px;
  left: 16px;
  z-index: 10;
  display: flex;
  gap: 8px;
  background: white;
  padding: 8px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.canvas-toolbar button {
  width: 32px;
  height: 32px;
  border: none;
  border-radius: 4px;
  background: #f8f9fa;
  color: #6c757d;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s;
}

.canvas-toolbar button:hover {
  background: #e9ecef;
  color: #495057;
}

.canvas-toolbar button.active {
  background: #007bff;
  color: white;
}

.flow-canvas {
  width: 100%;
  height: 100%;
  position: relative;
  overflow: auto;
  background: #f8f9fa;
}

.flow-canvas.hand {
  cursor: grab;
}

.flow-canvas.hand:active {
  cursor: grabbing;
}

.flow-canvas.connecting {
  cursor: crosshair;
}

.grid-container {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  pointer-events: none;
  background-size: 30px 30px;
  background-image: radial-gradient(circle at 1px 1px, #d0d7de 2px, transparent 2px);
}

.selection-box {
  position: fixed;
  border: 2px solid rgba(0, 123, 255, 0.5);
  background: rgba(0, 123, 255, 0.1);
  pointer-events: none;
  z-index: 1000;
}

.minimap {
  position: absolute;
  bottom: 16px;
  right: 16px;
  width: 200px;
  height: 150px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  overflow: hidden;
}

.minimap-content {
  position: relative;
  width: 100%;
  height: 100%;
}

.minimap-node {
  position: absolute;
  width: 20px;
  height: 12px;
  border-radius: 2px;
  background: #6c757d;
}

.minimap-node.selected {
  background: #007bff;
}

.minimap-viewport {
  position: absolute;
  border: 2px solid rgba(0, 123, 255, 0.5);
  background: rgba(0, 123, 255, 0.1);
  pointer-events: none;
}

/* 节点类型特定样式 */
.minimap-node.start-node {
  background: #28a745;
}

.minimap-node.model-node {
  background: #007bff;
}

.minimap-node.end-node {
  background: #dc3545;
}

.minimap-node.agent-node {
  background: #6f42c1;
}

.minimap-node.ifelse-node {
  background: #fd7e14;
}

.minimap-node.iterator-node {
  background: #20c997;
}

.minimap-node.code-node {
  background: #6c757d;
}

.minimap-node.template-node {
  background: #17a2b8;
}

.minimap-node.http-node {
  background: #e83e8c;
}

.minimap-node.database-node {
  background: #795548;
}

.json-tool-buttons {
  position: absolute;
  top: 16px;
  right: 16px;
  z-index: 10;
  display: flex;
  gap: 8px;
  background: white;
  padding: 8px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.json-tool-buttons button {
  padding: 8px 12px;
  border: none;
  border-radius: 4px;
  background: #f8f9fa;
  color: #6c757d;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  transition: all 0.2s;
}

.json-tool-buttons button:hover {
  background: #e9ecef;
  color: #495057;
}
</style>

<style>
/* 自定义端点样式 */
.jtk-endpoint.input-endpoint {
  opacity: 0 !important;
  /* 默认隐藏所有输入端点 */
  visibility: hidden !important;
  transition: opacity 0.3s ease, visibility 0.3s ease;
}

/* 规则1: 连接模式时显示所有左侧端点 */
body.connecting .jtk-endpoint.input-endpoint {
  opacity: 1 !important;
  visibility: visible !important;
}

/* 规则2: 已连接的端点始终可见 */
.jtk-endpoint.input-endpoint.connected-endpoint,
.jtk-endpoint.input-endpoint.jtk-endpoint-connected {
  opacity: 1 !important;
  visibility: visible !important;
}

/* 规则3: 源节点的左侧端点始终隐藏 */
body.connecting .source-node .jtk-endpoint.input-endpoint {
  opacity: 0 !important;
  visibility: hidden !important;
  display: none !important;
}

/* 规则4: 悬停时突出显示端点 */
.jtk-endpoint.input-endpoint:hover {
  transform: scale(1.2);
}
</style>